import { User } from "@prisma/client";
import * as jose from "jose";
import env from "../env";
import { nanoid } from "nanoid";
import _ from "lodash";
import log from "../log";
import AppError from "@/shared/app-error";

// 64bit-base64
const SECRET = Buffer.from(env.auth.hs512Secret, "base64");
const ISSUER = env.auth.tokenIssuer;

async function createJwt(user: User, expireTime: Date): Promise<string> {
  try {
    return await new jose.SignJWT({})
      .setProtectedHeader({ alg: "HS512" })
      .setSubject(user.id)
      .setJti(nanoid())
      .setExpirationTime(expireTime)
      .setIssuedAt(new Date())
      .setIssuer(ISSUER)
      .sign(SECRET);
  } catch (err) {
    log.error("jwt create failed: %s", user.id, err);
    throw new AppError({ code: "ERR_UNHANDLED", message: "创建令牌错误" });
  }
}

type JwtVerifyResult = { ok: true; userId: string; sessionId: string } | { ok: false; message: string };

async function verifyJwt(jwt: string): Promise<JwtVerifyResult> {
  try {
    const { payload } = await jose.jwtVerify(jwt, SECRET, { issuer: ISSUER });
    if (!payload.jti) {
      log.error("jwt has no jti: %s", { jwt, payload });
      return { ok: false, message: "token has no jti" };
    }
    const jti = payload.jti;

    if (!payload.sub) {
      log.error("jwt has no sub: %s", { jwt, payload });
      return { ok: false, message: "token has no sub" };
    }
    const userId = payload.sub;

    return { ok: true, userId, sessionId: jti };
  } catch (err) {
    log.error("jwt verify failed", err);
    return { ok: false, message: "unhandled error when jwt verifying" };
  }
}

const userJwtService = { createJwt, verifyJwt };

export default userJwtService;
